""" Klasse zur Verwaltung temporaerer Besucher 

gt = (datetime.now(), '123')
ptr = (datetime.now(), '321', set(['a','b']), True, +5)
ptf = (datetime.now(), '321', set(['a','b']), False, -2)

b = Besucher()
b.history_append('GET', gt)
b.history_append('POST', ptr)
b.history_append('POST', ptf)
b.put()

b.get_history('POST')
b.get_history('GET')
b.anz_bearbeitet('321') # 2 Mal
b.anz_bearbeitet('123') # 0 Mal, nur 'gesehen' (GET)
b.get_punktestand() # 3 = (+5) + (-2)

"""


# ein Besucher 
from google.appengine.ext import db 
import datetime

class Besucher(db.Model):
  """ history-format = liste aus tupeln:
      Post-History:
            0                    1               2                               3                   4
        [(datum+zeit  ,         akey,      meine_antworten = set(['a','b']), Richtig / Falsch, Punktegewinn)..]
           datetime.datetime    str             set                           bool             float
      Get-History:        
             0                   1
        [(Datum+Zeit,           akey))
          datetime.datetime     str
  """
  created = db.DateTimeProperty(auto_now_add = True)
  last_modified = db.DateTimeProperty(auto_now = True)
  cookie = db.StringProperty()
  history_POST = db.StringListProperty()
  history_GET = db.StringListProperty()
  
  def get_history(self, method):
    """ method = 'POST' oder 'GET' """
    if method not in set(['POST','GET']):
      raise Exception('wrong method: %s ' % method)
    elif method=='POST':
      return [eval(h) for h in self.history_POST]
    else:
      return [eval(h) for h in self.history_GET]

  def get_bearbeitungszeit(self, akey):
    """ Gibt die letzte Bearbeitungszeit in Sekunden an von diesem Besucher fuer die Aufgabe
        mit akey = 'akey'. Die Bearbeitungszeit wird folgendermassen ermittelt:
        Letzte History-Post-Zeit von Akey - letzte (welche kleiner sein muss als die Post-Zeit) History-Get-Zeit von Akey
        Wurde die Aufgabe noch nicht bearbeitet, so wird (zuerts, besser durchschnittzeit aller bearbeiteten aufgaben angeben) 300 Sekunden zurueckgegeben
    """
    if self.anz_bearbeitet(akey)>0:
      hg = self.get_history('GET')
      hp = self.get_history('POST')
      akey_get = [g for g in hg if g[1]==akey] # Liste Get-Eintraegen mit dem richtigen Akey
      akey_get.sort(reverse=True)             # sortieren nach Zeit, letzter Zeitpunkt zuerst
      akey_post = [p for p in hp if p[1]==akey]
      akey_post.sort(reverse=True)
      if len(akey_post) == 0 or len(akey_get) == 0:
        return 300
      post_zeitpunkt = akey_post[0][0]
      get_zeitpunkt = akey_get[0][0]
      time_delta = post_zeitpunkt - get_zeitpunkt #eine Instanz von datetime.timedelta
      return time_delta.seconds
    else:
      return 300

  def history_append(self, method, tuple):
    i = isinstance #zur Abkuerzung, damit die Zeile unten nich lang wird
    if method not in set(['POST','GET']):
      raise Exception('wrong method: %s ' % method)
    elif method=='POST':
      d,a,m,r,p = tuple
      tuple_ok = (len(tuple)==5) and i(d,datetime.datetime) and i(a,str) and i(m,set) and i(r,bool) and i(p,float)
      if tuple_ok:
        self.history_POST.append(str(tuple))
      else:
        raise Exception('Falsches Tuple Format fuer POST: %s' % str(tuple))
    elif method=='GET':
      d,a = tuple
      tuple_ok = (len(tuple)==2) and i(d,datetime.datetime) and i(a,str) 
      if tuple_ok:
        self.history_GET.append(str(tuple))
      else:
        raise Exception('Falsches Tuple Format fuer GET: %s' % str(tuple))


  def get_punktestand(self):
    """ gibt den aktuellen punktestand an
    """
    history = self.get_history('POST')
    return sum([h[4] for h in history])
    
  def anz_bearbeitet(self, akey):
    """ Wie oft hat der Besucher die Aufgabe mit akey bearbeitet?
    """
    return self.anz_richtig_gepostet(akey) + self.anz_falsch_gepostet(akey)

  def get_richtig_gepostet(self):
    """ Gibt eine Liste mit akeys zurueck, die nur ein Mal in der Liste auftauchen.
    """
    history = self.get_history('POST')
    akey_list = list(set([h[1] for h in history if h[3]]))
    return akey_list

  def anz_richtig_gepostet(self, akey):
    history = self.get_history('POST')
    akey_list = [h[1] for h in history if h[3]]
    return akey_list.count(akey)


  def anz_falsch_gepostet(self, akey):
    history = self.get_history('POST')
    akey_list = [h[1] for h in history if not h[3]]
    return akey_list.count(akey)


  def anz_richtig(self):
    history = self.get_history('POST')
    return len([h for h in history if h[3]])

  def get_fitness(self):
    """ Eine Zahl zwischen 0.0 und 1.0 , die angibt wie fit der Besucher ist.
        0.0 = nicht fit
        1.0 = top fit
        Momentane Berechnung: (Anzahl richtig bearbeiteter Aufgaben) / (Anzahl bearbeiteter Aufgaben)
                              Hat der Besucher noch keine Aufgaben berechnet, so wird 0.0 zurueckgegeben
    """
    history = self.get_history('POST')
    anz_bearbeitet = len(history)
    anz_richtig = len([h for h in history if h[3]])
    if anz_bearbeitet > 0:
      return 1.0*anz_richtig/anz_bearbeitet
    else:
      return 0.0
